package com.maozzi.web.auth;

import cn.hutool.core.util.ObjectUtil;
import com.maozzi.api.user.UserService;
import com.maozzi.api.user.model.UserDTO;
import com.maozzi.common.enums.BizCodeEnum;
import com.maozzi.common.exception.BizException;
import com.maozzi.common.util.CloneUtil;
import com.maozzi.common.util.TokenUtil;
import com.maozzi.web.auth.annotation.Login;
import com.maozzi.web.auth.constant.AuthConstant;
import com.maozzi.web.auth.model.UserInfo;
import com.maozzi.web.auth.util.SsoUtil;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 登录拦截器
 *
 * @author maozi
 */
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Resource
    private UserService userService;

    @Override
    public boolean preHandle(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) {
        String method = request.getMethod();
        if (HttpMethod.OPTIONS.matches(method)) {
            return true;
        }

        String url = request.getRequestURI();
        if (AuthConstant.ERROR_URLS.contains(url)) {
            return true;
        }

        // 检查是否@login 注解
        boolean needLogin = this.checkAnnotation(handler);
        if (!needLogin) {
            return true;
        }

        // 检查是否携带token
        String token = this.getToken(request);
        if (ObjectUtil.isEmpty(token)) {
            // 未登录
            throw new BizException(BizCodeEnum.NEED_LOGIN);
        }

        // 根据token查询用户info
        UserInfo userInfo = this.getUserInfo(token);
        if (ObjectUtil.isEmpty(userInfo)) {
            throw new BizException(BizCodeEnum.NEED_LOGIN);
        }

        SsoUtil.set(userInfo);

        return true;
    }

    /**
     * 检查是否@login 注解
     *
     * @param handler h
     * @return true-需要;false-不需要登录
     */
    private boolean checkAnnotation(Object handler) {
        Login annotation = null;
        // 如果是SpringMVC请求
        if (handler instanceof HandlerMethod handlerMethod) {
            annotation = handlerMethod.getMethodAnnotation(Login.class);
            if (ObjectUtil.isEmpty(annotation)) {
                annotation = handlerMethod.getBeanType().getAnnotation(Login.class);
            }
        }
        if (Objects.isNull(annotation)) {
            annotation = handler.getClass().getAnnotation(Login.class);
        }
        if (Objects.isNull(annotation)) {
            return false;
        }

        return annotation.require();
    }

    /**
     * 获取 header auth token
     *
     * @param request 请求
     * @return 返回
     */
    private String getToken(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION);
        if (Objects.isNull(token) || token.isBlank()) {
            return null;
        }

        return token.replace("Bearer", "").replaceAll(" ", "");
    }

    /**
     * 查询用户数据
     *
     * @param token 令牌
     * @return 返回
     */
    private UserInfo getUserInfo(String token) {
        // 1. 解析 token
        Long userId = TokenUtil.decodeToken(token);

        // 2. 校验用户基本信息
        UserDTO userDTO = userService.getUser(userId);
        if (Objects.isNull(userDTO) || Objects.isNull(userDTO.getId())) {
            log.error("LoginInterceptor 认证失败，原因：id={}用户基本信息查询不到", userId);

            return null;
        }

        return CloneUtil.to(userDTO, UserInfo.class);
    }

}
